﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Xml;
using Luxand;

namespace FaceRecognition
{
    public struct TFaceRecord
    {
        public byte[] Template; //Face Template;
        public FSDK.TFacePosition FacePosition;
        public FSDK.TPoint[] FacialFeatures; //Facial Features;

        public string ImageFileName;
        public UInt32 ImageHandle; // FSDK Image Handle
        public IntPtr ImageBmp; //HBitMap

        public UInt32 FaceImageHandle;
        public IntPtr FaceImageBmp;
    }

    public class Detector
    {
        public static float FaceDetectionThreshold = 1;
        public static float FARValue = 5;

        public Detector()
        {
            string LicenseKey = "14C0D9E9D7750AAC90F7109BFC63869A653F27D8D4C1E55354396A1396839E3477FBAFBB28A472A656F453D73269325945E123E522EBC9B31A5634475755333";
            
            if (FSDK.ActivateLibrary(LicenseKey) != FSDK.FSDKE_OK)
            {
                Console.WriteLine("Error activating Luxand FaceSDK.");
                return;
            }
            if (FSDK.Initialize("") != FSDK.FSDKE_OK)
            {
                Console.WriteLine("Error initializing FaceSDK.");
                return;
            }
        }
        public void detect(string fn)
        {
            try
            {
                //Assuming that faces are always vertical (HandleArbitraryRotations = false) to speed up face detection
                FSDK.SetFaceDetectionParameters(false, true, 384);
                FSDK.SetFaceDetectionThreshold((int)FaceDetectionThreshold);

                string uid = fn.Substring(0, fn.IndexOf("."));

                TFaceRecord fr = new TFaceRecord();
                fr.ImageHandle = 0;
                fr.ImageBmp = (IntPtr)0;
                fr.ImageFileName = fn;
                fr.FacePosition = new FSDK.TFacePosition();
                fr.FaceImageHandle = 0;
                fr.FaceImageBmp = (IntPtr)0;
                fr.FacialFeatures = new FSDK.TPoint[FSDK.FSDK_FACIAL_FEATURE_COUNT];
                fr.Template = new byte[92480];

                if (FSDK.LoadImageFromFile(ref fr.ImageHandle, fn) != FSDK.FSDKE_OK)
                    Console.WriteLine("Error loading file.");

                if (FSDK.SaveImageToHBitmap(fr.ImageHandle, ref fr.ImageBmp) != FSDK.FSDKE_OK)
                    Console.WriteLine("Error displaying picture.");

                if (FSDK.DetectFace(fr.ImageHandle, ref fr.FacePosition) != FSDK.FSDKE_OK){
                    Console.WriteLine("No faces found.");
                    return;
                }
                else
                {   
                    if (FSDK.DetectFacialFeaturesInRegion(fr.ImageHandle, ref fr.FacePosition, fr.FacialFeatures) != FSDK.FSDKE_OK)
                    {
                        Console.WriteLine("Error detection facial features.");
                    }
                    else
                    {
                        if (FSDK.GetFaceTemplateUsingFeatures(fr.ImageHandle, fr.FacialFeatures, fr.Template) != FSDK.FSDKE_OK)
                            Console.WriteLine("Error retrieving face template.", "Error");
                    }
                }
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;
                settings.IndentChars = ("    ");
                using (XmlWriter writer = XmlWriter.Create(uid+".xml", settings))
                {
                    writer.WriteStartElement("photo");
                    writer.WriteElementString("uid", uid.Substring(uid.LastIndexOf("\\")+1));
                    
                    writer.WriteStartElement("faceposition");
                    writer.WriteElementString("angle", fr.FacePosition.angle.ToString());
                    writer.WriteElementString("w", fr.FacePosition.w.ToString());
                    writer.WriteElementString("tl", "(" + ((int)(fr.FacePosition.xc - Math.Round(fr.FacePosition.w * 0.5))).ToString() + "," +
                        ((int)(fr.FacePosition.yc - Math.Round(fr.FacePosition.w * 0.5))).ToString() + ")");
                    writer.WriteElementString("tr", "(" + ((int)(fr.FacePosition.xc + Math.Round(fr.FacePosition.w * 0.5))).ToString() + "," +
                        ((int)(fr.FacePosition.yc - Math.Round(fr.FacePosition.w * 0.5))).ToString() + ")");
                    writer.WriteElementString("bl", "(" + ((int)(fr.FacePosition.xc - Math.Round(fr.FacePosition.w * 0.5))).ToString() + "," +
                        ((int)(fr.FacePosition.yc + Math.Round(fr.FacePosition.w * 0.5))).ToString() + ")");
                    writer.WriteElementString("tr", "(" + ((int)(fr.FacePosition.xc + Math.Round(fr.FacePosition.w * 0.5))).ToString() + "," +
                        ((int)(fr.FacePosition.yc + Math.Round(fr.FacePosition.w * 0.5))).ToString() + ")");
                    writer.WriteElementString("center", "(" + fr.FacePosition.xc.ToString() + "," + fr.FacePosition.yc.ToString() + ")");
                    writer.WriteEndElement();

                    writer.WriteStartElement("features");
                    int i = 0;
                    foreach (string s in Enum.GetNames(typeof(FSDK.FacialFeatures)))
                    {
                        writer.WriteElementString(s, "(" + fr.FacialFeatures[i].x.ToString() + "," + fr.FacialFeatures[i].y.ToString() + ")");
                        i++;
                    }
                    writer.WriteEndElement();

                    writer.WriteEndElement();
                    writer.Flush();
                }
                Console.WriteLine("0");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }

        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            foreach (string s in args)
            {
                Detector d = new Detector();
                d.detect(s);
            }
        }
    }
}
